Skip to content

04 os.path路径处理

处理文件路径是编程中最常见的操作之一。你想读取一个配置文件,得知道它的完整路径;想把上传的文件保存到指定目录,得拼接路径;想判断用户给的路径是不是一个真实存在的文件,也得用路径操作。

os.path是Python处理路径的传统方式,它提供了一组函数来拼接、拆分、检查路径。虽然现在有更现代的pathlib模块,但os.path的使用率依然非常高,很多老项目和第三方库都在用。

一、路径拼接

1.1 os.path.join()

把多个路径段拼接成一个完整路径,自动处理路径分隔符。

python
import os.path

# 拼接路径
os.path.join("data", "config", "settings.json")
# 'data/config/settings.json' (Linux/macOS)
# 'data\\config\\settings.json' (Windows)

# 可以拼接任意多的路径段
os.path.join("/Users/apple", "project", "data", "file.txt")
# '/Users/apple/project/data/file.txt'

# 绝对路径会覆盖前面的部分
os.path.join("data", "/tmp", "file.txt")
# '/tmp/file.txt'

# 空字符串会保留分隔符
os.path.join("data", "", "file.txt")
# 'data/file.txt'

为什么不用字符串拼接?

python
# 不推荐:手动拼接路径
path = "data" + "/" + "file.txt"

# 推荐:用os.path.join()
path = os.path.join("data", "file.txt")

原因很简单:Windows用反斜杠\,Linux/macOS用正斜杠/os.path.join()会自动处理这个差异。

二、路径拆分

2.1 os.path.basename()

获取路径的最后一部分(文件名或目录名)。

python
import os.path

os.path.basename("/Users/apple/data/file.txt")
# 'file.txt'

os.path.basename("/Users/apple/data/")
# ''  (以分隔符结尾时返回空字符串)

os.path.basename("/Users/apple/data")
# 'data'

2.2 os.path.dirname()

获取路径的目录部分(去掉最后一部分)。

python
import os.path

os.path.dirname("/Users/apple/data/file.txt")
# '/Users/apple/data'

os.path.dirname("/Users/apple/data/")
# '/Users/apple/data'

os.path.dirname("/Users/apple/data")
# '/Users/apple'

os.path.dirname("file.txt")
# ''  (没有目录部分时返回空字符串)

2.3 os.path.split()

同时获取目录和文件名,返回元组。

python
import os.path

os.path.split("/Users/apple/data/file.txt")
# ('/Users/apple/data', 'file.txt')

# 等价于
dirpath = os.path.dirname(path)
filename = os.path.basename(path)

2.4 os.path.splitext()

分离文件名和扩展名。

python
import os.path

os.path.splitext("file.txt")
# ('file', '.txt')

os.path.splitext("archive.tar.gz")
# ('archive.tar', '.gz')

os.path.splitext("/Users/apple/data/file.txt")
# ('/Users/apple/data/file', '.txt')

os.path.splitext("Makefile")
# ('Makefile', '')  (没有扩展名时返回空字符串)

2.5 os.path.splitdrive()

分离驱动器号(Windows)。

python
import os.path

# Windows路径
os.path.splitdrive("C:/Users/apple/data.txt")
# ('C:', '/Users/apple/data.txt')

# 非Windows路径
os.path.splitdrive("/Users/apple/data.txt")
# ('', '/Users/apple/data.txt')

三、路径检查

3.1 os.path.exists()

检查路径是否存在(文件或目录都可以)。

python
import os.path

os.path.exists("/Users/apple")      # True
os.path.exists("/not/exist/path")   # False
os.path.exists("data.txt")          # True 或 False(取决于当前目录)

3.2 os.path.isfile() / os.path.isdir()

分别检查是文件还是目录。

python
import os.path

os.path.isfile("/Users/apple/data.txt")    # True(是文件)
os.path.isfile("/Users/apple/project")     # False(是目录)
os.path.isfile("/not/exist")               # False(不存在)

os.path.isdir("/Users/apple/project")      # True(是目录)
os.path.isdir("/Users/apple/data.txt")     # False(是文件)

检查是否为符号链接。

python
import os.path

os.path.islink("/usr/local/bin/python")
# 可能是True(如果是符号链接)

3.4 os.path.isabs()

检查是否为绝对路径。

python
import os.path

os.path.isabs("/Users/apple/data.txt")  # True
os.path.isabs("data.txt")               # False
os.path.isabs("./data.txt")             # False
os.path.isabs("../data.txt")            # False

四、路径转换

4.1 os.path.abspath()

获取绝对路径(解析...)。

python
import os.path

os.path.abspath(".")
# '/Users/apple/project'  (当前目录的绝对路径)

os.path.abspath("data.txt")
# '/Users/apple/project/data.txt'

os.path.abspath("../data.txt")
# '/Users/apple/data.txt'

os.path.abspath("~/data.txt")
# '/Users/apple/project/~/data.txt'  (不会展开~)

4.2 os.path.realpath()

解析符号链接,获取真实路径。

python
import os.path

# 如果/path是符号链接,realpath会解析到真实目标
os.path.realpath("/usr/local/bin/python")
# '/usr/bin/python3.14'

4.3 os.path.normpath()

规范化路径(折叠多余的分隔符和...)。

python
import os.path

os.path.normpath("/Users/apple//project/../data/./file.txt")
# '/Users/apple/data/file.txt'

os.path.normpath("./data/../file.txt")
# 'file.txt'

# Windows上还会转为反斜杠
os.path.normpath("C:/Users/apple/data.txt")
# 'C:\\Users\\apple\\data.txt' (Windows)

4.4 os.path.relpath()

计算相对路径。

python
import os.path

os.path.relpath("/Users/apple/project", "/Users/apple")
# 'project'

os.path.relpath("/Users/apple/data.txt", "/Users/apple/project")
# '../data.txt'

# 默认相对于当前目录
os.path.relpath("/Users/apple/data.txt")
# 计算从当前目录到目标的相对路径

4.5 os.path.expanduser()

展开~为用户主目录。

python
import os.path

os.path.expanduser("~/data.txt")
# '/Users/apple/data.txt'

os.path.expanduser("~otheruser/data.txt")
# '/Users/otheruser/data.txt' (如果存在)

os.path.expanduser("data.txt")
# 'data.txt' (没有~时不变化)

4.6 os.path.expandvars()

展开路径中的环境变量。

python
import os

os.environ["MY_DATA"] = "/opt/data"

os.path.expandvars("$MY_DATA/file.txt")
# '/opt/data/file.txt'

os.path.expandvars("${MY_DATA}/file.txt")
# '/opt/data/file.txt'

五、文件信息

5.1 os.path.getsize()

获取文件大小(字节)。

python
import os.path

size = os.path.getsize("data.txt")
print(f"文件大小: {size} 字节")

# 人类可读的大小
def format_size(size):
    for unit in ['B', 'KB', 'MB', 'GB']:
        if size < 1024:
            return f"{size:.1f} {unit}"
        size /= 1024
    return f"{size:.1f} TB"

print(format_size(os.path.getsize("data.txt")))

5.2 文件时间

python
import os.path
import time

# 最后修改时间
mtime = os.path.getmtime("data.txt")
print(f"修改时间: {time.ctime(mtime)}")

# 最后访问时间
atime = os.path.getatime("data.txt")

# 创建时间(Windows)/ 元数据修改时间(Unix)
ctime = os.path.getctime("data.txt")

5.3 os.path.samefile()

检查两个路径是否指向同一个文件。

python
import os.path

os.path.samefile("/Users/apple/data.txt", "/Users/apple/../apple/data.txt")
# True(解析后是同一个文件)

六、常用模式

6.1 获取文件扩展名

python
import os.path

def get_extension(filepath):
    _, ext = os.path.splitext(filepath)
    return ext.lower()

get_extension("photo.jpg")      # '.jpg'
get_extension("archive.tar.gz") # '.gz'
get_extension("Makefile")       # ''

6.2 替换扩展名

python
import os.path

def change_extension(filepath, new_ext):
    root, _ = os.path.splitext(filepath)
    return root + new_ext

change_extension("data.txt", ".json")  # 'data.json'
change_extension("photo.jpg", ".png")  # 'photo.png'

6.3 遍历目录找特定文件

python
import os
import os.path

def find_files(directory, ext):
    """查找指定目录下所有特定扩展名的文件"""
    result = []
    for root, dirs, files in os.walk(directory):
        for f in files:
            if f.endswith(ext):
                result.append(os.path.join(root, f))
    return result

# 找到所有Python文件
py_files = find_files(".", ".py")

6.4 安全地创建目录

python
import os
import os.path

def ensure_dir(path):
    """确保目录存在,不存在则创建"""
    if not os.path.exists(path):
        os.makedirs(path, exist_ok=True)

ensure_dir("data/2026/06")

6.5 获取脚本所在目录

python
import os.path

# 获取当前脚本的绝对路径
script_path = os.path.abspath(__file__)

# 获取脚本所在目录
script_dir = os.path.dirname(script_path)

# 常用:相对于脚本位置读取配置
config_path = os.path.join(script_dir, "config.json")

七、与pathlib的对比

os.path是函数式风格,pathlib是面向对象风格。功能上等价:

python
# os.path风格
import os.path
path = os.path.join("data", "file.txt")
exists = os.path.exists(path)
name = os.path.basename(path)

# pathlib风格
from pathlib import Path
path = Path("data") / "file.txt"
exists = path.exists()
name = path.name

如果你的项目是新写的,推荐用pathlib。如果是维护老代码,os.path完全够用。

八、总结

os.path的核心就是路径的拼接、拆分、检查、转换:

分类常用函数
拼接join()
拆分basename(), dirname(), split(), splitext(), splitdrive()
检查exists(), isfile(), isdir(), islink(), isabs()
转换abspath(), realpath(), normpath(), relpath(), expanduser(), expandvars()
信息getsize(), getmtime(), getatime(), getctime(), samefile()

记住join()exists()basename()dirname()splitext()这五个,就能覆盖80%的场景。